# _*_ coding:utf-8 _*_
# @File  : datetime_utils.py
# @Time  : 2022-02-08  08:27
# @Author: zizle

import calendar
import datetime
from typing import Union

from dateutil import rrule
from global_constant import DATES


def to_string(obj: Union[datetime.date, datetime.datetime], f='%Y-%m-%d', is_time=False):
    if not obj:
        return ''
    if is_time:
        f = f + ' %H:%M:%S'
    return obj.strftime(f)


def today_timestamp(millisecond=False):
    ts = datetime.datetime.today().timestamp()
    return int(ts * 1000) if millisecond else int(ts)


def today(f='%Y%m%d', obj=False):
    return datetime.datetime.now() if obj else datetime.datetime.now().strftime(f)


def yesterday(f='%Y%m%d'):
    return (datetime.datetime.today() + datetime.timedelta(days=-1)).strftime(f)


def timestamp_formatter(ts, f='%Y-%m-%d'):
    return datetime.datetime.fromtimestamp(ts).strftime(f)


def exchange_date_nearby(date_node: datetime.datetime, mode='previous', f='%Y-%m-%d', ts=False):
    delta_day = -1 if mode == 'previous' else 1
    if date_node.isoweekday() <= 5 and date_node.strftime('%Y-%m-%d') not in DATES.HOLIDAYS:
        return int(date_node.timestamp()) if ts else date_node.strftime(f)
    date_node = date_node + datetime.timedelta(days=delta_day)
    return exchange_date_nearby(date_node, ts=ts, f=f)


def year_start_end(year: int, ts: bool = False):  # 获取年份的起始
    f = '%Y-%m-%d %H:%M:%S'
    if year < 2000:
        raise ValueError('参数year需大于2000.')
    s = datetime.datetime.strptime(f'{year}-01-01 00:00:00', f)
    e = datetime.datetime.strptime(f'{year}-12-31 23:59:59', f)
    if ts:
        return int(s.timestamp()), int(e.timestamp())
    else:
        return s.strftime(f), e.strftime(f)


def month_start_end(year: int, month: int, ts: bool = False, rf='%Y-%m-%d %H:%M:%S'):  # 获取月份的起始
    if year < 2000 or month < 1 or month > 12:
        raise ValueError('参数year需大于2000， month需为1~12之间')
    _, end_day = calendar.monthrange(year, month)
    f = '%Y-%m-%d %H:%M:%S'
    s = datetime.datetime.strptime(f'{year}-{month}-01 00:00:00', f)
    e = datetime.datetime.strptime(f'{year}-{month}-{end_day} 23:59:59', f)
    if ts:
        return int(s.timestamp()), int(e.timestamp())
    else:
        return s.strftime(rf), e.strftime(rf)


def auth_datetime_string(datetime_string: str, f: str = '%Y-%m-%d %H:%M:%S', ts: bool = False, rf=None):
    if not datetime_string:
        return None
    if not rf:
        rf = f
    try:
        obj = datetime.datetime.strptime(datetime_string, f)
    except ValueError:
        return None
    return int(obj.timestamp()) if ts else obj.strftime(rf)


def date_of_year(year=None):  # 返回一年内的每一天
    if not year:
        year = datetime.datetime.today().year
    date_list = []

    start = datetime.datetime.strptime('%d-01-01' % year, '%Y-%m-%d')
    end = datetime.datetime.strptime('%d-12-31' % year, '%Y-%m-%d')
    while start <= end:
        date_list.append(start.strftime('%m-%d'))
        start += datetime.timedelta(days=1)
    return date_list


def month_of_range(start, end, ft='%Y-%m-%d'):  # 月份列表
    month_list = []
    start_date = datetime.datetime.strptime(start, ft)
    end_date = datetime.datetime.strptime(end, ft)
    while start_date <= end_date:
        month = start_date.strftime('%Y%m')
        if month not in month_list:
            month_list.append(month)
        start_date += datetime.timedelta(days=10)
    return month_list


def get_current_quarter_start_end(date: datetime.datetime):  # 获取指定日期的本季度第一天和最后一天
    quarter = (date.month - 1) // 3 + 1
    if quarter == 1:
        s = datetime.datetime.strptime(f'{date.year}-01-01', '%Y-%m-%d')
        e = datetime.datetime.strptime(f'{date.year}-03-31', '%Y-%m-%d')
    elif quarter == 2:
        s = datetime.datetime.strptime(f'{date.year}-04-01', '%Y-%m-%d')
        e = datetime.datetime.strptime(f'{date.year}-06-30', '%Y-%m-%d')
    elif quarter == 3:
        s = datetime.datetime.strptime(f'{date.year}-07-01', '%Y-%m-%d')
        e = datetime.datetime.strptime(f'{date.year}-09-30', '%Y-%m-%d')
    else:
        s = datetime.datetime.strptime(f'{date.year}-10-01', '%Y-%m-%d')
        e = datetime.datetime.strptime(f'{date.year}-12-31', '%Y-%m-%d')
    return s, e


def get_quarter(date: datetime.datetime):
    month = int(date.strftime('%m'))
    if 1 <= month <= 3:
        q = 1
    elif 3 < month <= 6:
        q = 2
    elif 6 < month <= 9:
        q = 3
    else:
        q = 4
    return '%d%02d' % (date.year, q)


def get_current_month_start_end(year, month):  # 获取指定月份的第一天和最后一天
    _, end_day = calendar.monthrange(year, month)
    month_start = datetime.datetime.strptime(f'{year}-{month}-01', '%Y-%m-%d')
    month_end = datetime.datetime.strptime(f'{year}-{month}-{end_day}', '%Y-%m-%d')
    return month_start, month_end


def date_interval(s: datetime.date, e: datetime.date, to_string: bool = False):  # 计算2个日期之间的间隔
    year_sep = rrule.rrule(rrule.YEARLY, dtstart=s, until=e)
    tmp_year = year_sep.count() - 1
    # 计算月
    s = datetime.date(s.year + tmp_year, s.month, s.day)
    month_sep = rrule.rrule(rrule.MONTHLY, dtstart=s, until=e)
    tmp_month = month_sep.count() - 1
    # 计算天
    new_year = s.year
    new_month = s.month + tmp_month  # 默认正常加上月份数
    delta_month = tmp_month - 12 + s.month  # 到12月还剩余的月份数
    if delta_month > 0:
        new_year = s.year + 1
        new_month = delta_month
    s = datetime.date(new_year, new_month, s.day)
    day_sep = rrule.rrule(rrule.DAILY, dtstart=s, until=e)
    tmp_day = day_sep.count() - 1 if day_sep.count() > 0 else 0
    # 结束日当月的最后一天
    if e.month + 1 > 12:
        cur_month_last = datetime.date(e.year + 1, 1, 1) - datetime.timedelta(days=1)
    else:
        cur_month_last = datetime.date(e.year, e.month + 1, 1) - datetime.timedelta(days=1)
    # 结束日当月的天数
    end_month_day_count = (cur_month_last - datetime.date(e.year, e.month, 1)).days
    if tmp_day >= end_month_day_count:  # 大于结束当月的天数，则需加一个月
        tmp_month = tmp_month + 1
        tmp_day = tmp_day - end_month_day_count
        if tmp_month >= 12:
            tmp_year = tmp_year + 1
            tmp_month = 0
    if to_string:
        duration_str = ""
        if tmp_year > 0:
            duration_str += f'{tmp_year}年'
        if tmp_month > 0:
            duration_str += f'{tmp_month}个月'
        if tmp_day > 0:
            duration_str += f'{tmp_day}天'
        return duration_str
    return tmp_year, tmp_month, tmp_day


def format_integer_date(date_integer, f='%Y%m%d', rf='%Y%m%d', obj=True):
    o_date = datetime.datetime.strptime(str(date_integer), f)
    if obj:
        return datetime.date(o_date.year, o_date.month, o_date.day)
    else:
        return o_date.strftime(rf)


def frequency_delta_days(cur: Union[datetime.date, datetime.datetime], frequency):
    if frequency == '周':  # 获取cur的上一个周一
        t_date = cur - datetime.timedelta(days=cur.isoweekday() - 1 + 7)  # 上周星期一
    elif frequency == '月':  # 获取上月1日
        ms, _ = get_current_month_start_end(cur.year, cur.month)  # 本月开始
        pme = ms - datetime.timedelta(days=1)
        t_date, _ = get_current_month_start_end(pme.year, pme.month)  # 上月1日
    elif frequency == '季':  # 取上一个季度开始日
        qs, _ = get_current_quarter_start_end(cur)  # 本季度开始
        tmp = qs - datetime.timedelta(days=1)
        t_date, _ = get_current_quarter_start_end(tmp)
    elif frequency == '年':  # 去上一年1月1日
        t_date = datetime.date(cur.year - 1, 1, 1)
    else:
        t_date = cur

    _cur = datetime.date(cur.year, cur.month, cur.day)
    _tad = datetime.date(t_date.year, t_date.month, t_date.day)
    return (_cur - _tad).days
